import { noop, query } from "../util/index.js";
import { compileToFunctions } from "./compiler.js";
import config from "./config.js";
import { mergeOptions } from "./options.js";
import { createPatchFunction } from "./patch.js";
import { idToTemplate } from "./util.js";
import { createEmptyVNode } from "./vdom.js";
import nodeOps from "./nodeOps.js";

function Vue(options) {
  if (!(this instanceof Vue)) {
    console.warn("使用new关键字来调用Vue");
  }
  this._init(options);
}

Vue.prototype._init = function (options) {
  const vm = this;
  vm._isVue = true;
  vm.$options = mergeOptions(
    // resolveConstructorOptions(vm.constructor),
    {},
    options || {},
    vm
  );
};

Vue.prototype.$mount = function (el, hydrating) {
  el = query(el);
  const options = this.$options;
  if (!options.render) {
    let template = options.template;
    if (typeof template === "string") {
      if (template.charAt(0) === "#") {
        template = idToTemplate(template);
      }
    } else if (template.nodeType) {
      template = template.innerHTML;
    } else {
      return this;
    }
    if (template) {
      const { render, staticRenderFns } = compileToFunctions(
        template,
        {},
        // this
      );
      options.render = render;
      options.staticRenderFns = staticRenderFns;
    }
  }
  mountComponent(this, el, hydrating);
};

function mountComponent(vm, el, hydrating) {
  vm.$el = el;
  if (!vm.$options.render) {
    vm.$options.render = createEmptyVNode;
  }
  // callHook(vm, "beforeMount");
  console.log(vm._render());
  vm._update(vm._render(), hydrating);
  if (vm.$vnode == null) {
    vm._isMounted = true;
    // callHook(vm, "mounted");
  }
  return vm;
}

Vue.prototype._render = function () {
  const vm = this;
  const { render } = vm.$options;
  console.log('render', render);
  return render.call(vm._renderProxy, vm.$createElement);
};

Vue.prototype._update = function (vnode, hydrating) {
  const vm = this;
  const preVnode = vm._vnode;

  console.log('vm', vm);
  if (!preVnode) {
    // 第一次渲染
    vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false);
  } else {
    vm.$el = vm.__patch__(preVnode, vnode);
  }
};

Vue.prototype.__patch__ = createPatchFunction({ nodeOps });

Vue.config = config;

export default Vue;
